Skip to content

(feat) [ONR-511] Migration to Nitro Modules#1

Merged
YouCanKeepSilence merged 26 commits into
masterfrom
feat/ONR-511-nitro-modules
Jun 2, 2026
Merged

(feat) [ONR-511] Migration to Nitro Modules#1
YouCanKeepSilence merged 26 commits into
masterfrom
feat/ONR-511-nitro-modules

Conversation

@YouCanKeepSilence

Copy link
Copy Markdown
Collaborator

This allow us to serve RN without Expo

YouCanKeepSilence and others added 17 commits May 29, 2026 15:29
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Install react-native-nitro-modules@0.35.9 (peerDep) + nitrogen@0.35.9 (devDep)
- Add nitro.json config with onramper namespace
- Add nitrogen codegen script
- Podspec: remove ExpoModulesCore dep, narrow source_files to Hybrid*.swift/Nitro*.swift
- Delete expo-module.config.json (Expo autolinking manifest)
…native.config.js

- src/specs/OnramperNitro.nitro.ts + nitrogen-generated specs
- ios/HybridOnramperNitro.swift (Promise.async)
- nitro.json autolinking (0.35.9 ios.implementationClassName form)
- react-native.config.js (package) + example-bare/react-native.config.js (consumer,
  explicit root+podspecPath) so RN-CLI autolinks the package through the file:.. symlink
- pod install links both NitroModules + OnramperReactNative

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ense :file

- package-side react-native.config.js used dependency.platforms.ios.podspecPath,
  which RN 0.85 CLI rejects as invalid (warns on every launch). The example links
  via the consumer-side example-bare/react-native.config.js instead.
  Real-consumer (npm-install) autolinking to be validated in Phase 4.
- podspec license dropped the unreadable ../LICENSE :file reference.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
RN 0.81+ defaults to a precompiled React Native Core whose distribution
doesn't expose module maps for Swift, causing 'No such module React' in the
stock AppDelegate.swift and our Nitro pod (cascading to HybridOnramperNitroSpec
not in scope). Set ENV in the Podfile to build RN core from source.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…resolve

nitrogen's add_nitrogen_files appends source globs (nitrogen/generated/**)
relative to the podspec dir. With the podspec in ios/, those resolved to
ios/nitrogen/** (nonexistent), so the generated HybridOnramperNitroSpec.swift
was never compiled -> 'cannot find type HybridOnramperNitroSpec in scope'.
Moved podspec to repo root (Nitro convention); ios/-prefixed our own sources.

Also includes example-bare Podfile SWIFT_ENABLE_EXPLICIT_MODULES=NO fix (Xcode 26
explicit modules -> module map not found) and consumer config podspecPath update.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…sh nitrogen output

Validated empirically (prebuilt-core ON + explicit-modules OFF builds clean):
SWIFT_ENABLE_EXPLICIT_MODULES=NO is the sole required RN0.85/Xcode26 fix — it
also resolves the earlier 'No such module React', so the faster precompiled
React Native Core can stay enabled. Removed the source-build override.

package.json files: add nitrogen/generated + the root OnramperReactNative.podspec
so real npm consumers get the generated specs and podspec.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- #2 sdkProbe(): import OnramperSDK, construct a real Environment value — proves
  the vendored xcframework links under Nitro's Swift/C++ interop.
- #3 HybridNitroSpikeView: a Nitro View hosting SwiftUI via UIHostingController
  (Phase 2's checkout-button pattern). View spec scoped to { ios: 'swift' } since
  Nitro views otherwise demand a Kotlin impl too.
- #4 startTicker/stopTicker: stores a JS callback natively + fires on a timer
  (event-stream mechanism); stopTicker releases it (cleanup path).
- podspec: add install_modules_dependencies(s) for RN new-arch Fabric/Yoga
  header paths (Nitro view pulls in React-Fabric -> yoga/style/Style.h).

Verified: BUILD SUCCEEDED on iOS simulator.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ble in dark mode

Spike gate passed on device: proofs #1-#4 all confirmed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… + events + session

Replaces the Expo Modules bridge with a Nitro HybridObject wrapping
OnramperSDK.OnramperClient, designed against the SDK (not the Expo-era bridge):
- HybridOnramperNitro.swift: wraps OnramperClient; mirrors $state (Combine) and
  the events AsyncStream to single JS callbacks; feeds sessionExpirationHandler
  directly from a stored Nitro async callback (drops the token/continuation dance).
- OnramperSDKBridge.swift: SDK enum -> JS dict mapping + JSON-string transport
  (OnramperState/CheckoutEvent are non-Codable); error code/info, no [info:] folding.
- OnramperClient.ts: same public API (initialize/reset/signOut/addStateListener/
  addEventListener/destroy); per-client native instance; JSON parsed to typed unions.
- errors.ts: dropped the Expo message-folding regex.
- Removed spike code + the Expo checkout view (returns as a Nitro view in Phase 2).
- package.json: source/react-native field so the example bundles from src.

Verified: BUILD SUCCEEDED on iOS simulator.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- new react-native-nitro-modules mock (per-instance createHybridObject capturing
  the registered state/event/session callbacks); drop the expo-modules-core mock.
- OnramperClient.test: cover configure/initialize/signOut, session-handler
  resolve+reject, state/event fan-out, and destroy()->dispose(). 12 passing.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…uirements

- OnramperCheckoutButton Nitro view (HybridOnramperCheckoutButton.swift) hosts the
  SDK's SwiftUI OnramperCheckoutButton via UIHostingController, consumed from
  PreparedIntentRegistry.shared by handle; re-attaches as a child VC so the button
  can present its login/webview sheets.
- getCheckoutRequirements/cancelPreparedIntent on HybridOnramperNitro: decode the
  JSON request/style (OnramperCheckoutBridge.swift), call the SDK, stash the button
  by ULID handle, return { intentHandle, quoteJson }.
- PreparedIntentRegistry: shared singleton (module stores, view consumes by handle).
- OnramperClient.ts: getCheckoutRequirements (returns a button element + quote) +
  cancelPreparedIntent restored; OnramperCheckoutButtonView re-added as a Nitro view.
- Deleted all remaining legacy Expo Swift (module + view + Bridging/*); podspec
  source_files simplifies to ios/*.swift. tsconfig: resolveJsonModule for the
  generated view config.

Verified: BUILD SUCCEEDED on iOS simulator; typecheck/lint/jest(12) green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The current OnramperSDK adds 5 provider-lifecycle events (providerReady,
paymentAuthorized, paymentProcessing, paymentCancelled, providerError) emitted by
third-party checkout webviews. Map them in OnramperSDKBridge.toJSDict() + add them
to the typed CheckoutEvent union. Surfaced by rebuilding the xcframework from the
current onramper-sdk source (which also carries the ff29281 App Attest self-heal).

Note: the vendored xcframework is gitignored (fetched per release); this commit is
the wrapper-side event handling. A proper SDK release should ship the new binary.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replace the last loose `response: unknown` with CheckoutFinalizeResponse /
HeadlessCheckoutData mirrored from Sources/OnramperSDK/Models/CheckoutFinalizeResponse.swift,
and export them. (errors.ts info stays Record<string,unknown> — genuinely open-ended.)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
app.plugin.js applies the two iOS requirements that aren't Expo defaults:
- ios.deploymentTarget 16.4 (vendored OnramperSDK.xcframework requires it)
- SWIFT_ENABLE_EXPLICIT_MODULES=NO (Xcode 16+/26 + CocoaPods + Swift pods)
Registered in package.json files; @expo/config-plugins as a devDep.

example/ (Expo) wired to consume the Nitro package: react-native-nitro-modules dep,
newArchEnabled, the plugin in app.json, bundle id com.onramper.demo.react-native-expo
(distinct from the bare example so both coexist on-device), prebuilt + BUILD SUCCEEDED.

Notable: Expo autolinking discovers the package's root podspec automatically — no
consumer react-native.config.js needed (unlike the bare RN-CLI + file:.. symlink case).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The example consumes the package via file:.., and Metro's symlink-dedup config
(disableHierarchicalLookup + nodeModulesPaths=[example/node_modules]) requires the
Nitro peer dep to be physically in example/node_modules. Installed with
--legacy-peer-deps (pre-existing @react-native/new-app-screen 0.85.2-vs-0.85.3 peer
mismatch) + --ignore-scripts (the file:.. package's expo-module prepare otherwise
clobbers tsconfig.json + fails). Restores tsconfig resolveJsonModule.

NOTE: expo-module-scripts' prepare regenerating tsconfig.json is fragile — Phase 4
should drop expo-module-scripts (→ plain tsc) to stop the clobbering.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Public-facing docs were still written for the Expo Modules era. Updated to the
Nitro reality:
- Install: react-native-nitro-modules peer dep + New Architecture; bare RN and
  Expo (via the bundled config plugin) — dropped install-expo-modules and the
  mandatory ExpoReactNativeFactory AppDelegate section entirely.
- iOS setup: bare-RN Podfile (deployment target 16.4 + SWIFT_ENABLE_EXPLICIT_MODULES=NO);
  Metro/Babel use standard RN defaults for bare RN.
- Events: documented the 5 provider-lifecycle events; removed the obsolete
  'checkoutCancelled not surfaced' + per-view-handler caveats.
- Cleanups: dropped the objectVersion sed workaround, fixed the file:.. symlink
  contributor note (Nitro module names + bare-RN autolinking), converted the
  going-live checklist to plain bullets (no checkbox/todo rendering).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@YouCanKeepSilence YouCanKeepSilence self-assigned this Jun 1, 2026
Copilot AI review requested due to automatic review settings June 1, 2026 12:31
@linear

linear Bot commented Jun 1, 2026

Copy link
Copy Markdown

ONR-511

Review in Linear

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR migrates the library from an Expo Modules–based native bridge to Nitro Modules/Nitrogen-generated HybridObjects, enabling consumption in bare React Native (without Expo) while keeping an Expo integration path via a config plugin.

Changes:

  • Replaces the Expo Modules native module/event emitter with a per-OnramperClient Nitro HybridObject + single-callback state/event streams.
  • Adds Nitro/Nitrogen specs and generated bridge code (C++/Swift), plus a root podspec for New Architecture builds.
  • Updates packaging/docs/examples/tests to depend on react-native-nitro-modules, include generated artifacts, and support Expo prebuild via app.plugin.js.

Reviewed changes

Copilot reviewed 86 out of 144 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
tsconfig.json Enables JSON module imports and includes Nitrogen-generated JSON in TS compilation.
src/types.ts Adds typed CheckoutFinalizeResponse/HeadlessCheckoutData surfaced through events.
src/specs/OnramperNitro.nitro.ts Defines the Nitro HybridObject surface (configure/init/state+event listeners/session handler).
src/specs/OnramperCheckoutButton.nitro.ts Defines the Nitro-hosted native checkout button view props.
src/OnramperNative.ts Replaces Expo requireNativeModule with NitroModules.createHybridObject(...).
src/OnramperClient.ts Reworks JS client to own a native HybridObject instance and parse/fan-out JSON callbacks.
src/OnramperCheckoutButtonView.tsx Replaces Expo view manager with Nitro getHostComponent(...) + generated view config JSON.
src/index.ts Exports new finalize/checkout response types.
src/events.ts Types checkoutFinalized and adds provider lifecycle events.
src/errors.ts Simplifies OnramperError.from for structured {code,message,info} errors.
README.md Updates install/requirements/docs for Nitro + New Architecture + Expo plugin usage.
package.json Switches deps/peers to Nitro, publishes generated artifacts, adds root entry points.
OnramperReactNative.podspec New root podspec integrating Nitrogen-generated files + RN new-arch deps.
nitrogen/generated/shared/json/OnramperCheckoutButtonConfig.json Generated host component config for the Nitro view.
nitrogen/generated/shared/c++/views/HybridOnramperCheckoutButtonComponent.hpp Generated Fabric component definitions for the Nitro view.
nitrogen/generated/shared/c++/views/HybridOnramperCheckoutButtonComponent.cpp Generated Fabric component implementation for the Nitro view.
nitrogen/generated/shared/c++/PreparedIntentResult.hpp Generated C++ struct for prepared intent results (handle + quote JSON).
nitrogen/generated/shared/c++/OnramperNitroConfig.hpp Generated C++ struct for Nitro configuration.
nitrogen/generated/shared/c++/NitroSessionCredentials.hpp Generated C++ struct for session credentials returned by JS handler.
nitrogen/generated/shared/c++/HybridOnramperNitroSpec.hpp Generated C++ HybridObject spec for the Nitro module.
nitrogen/generated/shared/c++/HybridOnramperNitroSpec.cpp Generated HybridObject method registration.
nitrogen/generated/shared/c++/HybridOnramperCheckoutButtonSpec.hpp Generated C++ HybridView spec for the checkout button.
nitrogen/generated/shared/c++/HybridOnramperCheckoutButtonSpec.cpp Generated HybridView method/property registration.
nitrogen/generated/ios/swift/PreparedIntentResult.swift Generated Swift typealias/bridging for PreparedIntentResult.
nitrogen/generated/ios/swift/OnramperNitroConfig.swift Generated Swift typealias/bridging for config struct.
nitrogen/generated/ios/swift/NitroSessionCredentials.swift Generated Swift typealias/bridging for credentials struct.
nitrogen/generated/ios/swift/HybridOnramperNitroSpec.swift Generated Swift protocol/base wiring for the Nitro HybridObject.
nitrogen/generated/ios/swift/HybridOnramperCheckoutButtonSpec.swift Generated Swift protocol/base wiring for the Nitro HybridView.
nitrogen/generated/ios/swift/HybridOnramperCheckoutButtonSpec_cxx.swift Generated Swift↔C++ wrapper for the HybridView.
nitrogen/generated/ios/swift/Func_void.swift Generated closure wrapper for Swift→C++ bridging.
nitrogen/generated/ios/swift/Func_void_std__string.swift Generated closure wrapper for string callback bridging.
nitrogen/generated/ios/swift/Func_void_std__shared_ptr_Promise_NitroSessionCredentials__.swift Generated closure wrapper for promise bridging.
nitrogen/generated/ios/swift/Func_void_std__exception_ptr.swift Generated closure wrapper for error bridging.
nitrogen/generated/ios/swift/Func_void_PreparedIntentResult.swift Generated closure wrapper for PreparedIntentResult bridging.
nitrogen/generated/ios/swift/Func_void_NitroSessionCredentials.swift Generated closure wrapper for credentials bridging.
nitrogen/generated/ios/swift/Func_std__shared_ptr_Promise_std__shared_ptr_Promise_NitroSessionCredentials____.swift Generated wrapper for nested promise callback return bridging.
nitrogen/generated/ios/OnramperReactNativeAutolinking.swift Generated Swift factory functions used by Nitro autolinking.
nitrogen/generated/ios/OnramperReactNativeAutolinking.mm Generated ObjC++ registration into Nitro HybridObjectRegistry.
nitrogen/generated/ios/OnramperReactNative+autolinking.rb Generated podspec helper adding Nitrogen sources/flags/deps.
nitrogen/generated/ios/OnramperReactNative-Swift-Cxx-Umbrella.hpp Generated umbrella header for Swift/C++ bridging.
nitrogen/generated/ios/OnramperReactNative-Swift-Cxx-Bridge.cpp Generated C++ glue for Swift closure/type bridging.
nitrogen/generated/ios/c++/views/HybridOnramperCheckoutButtonComponent.mm Generated iOS Fabric component view holder implementation.
nitrogen/generated/ios/c++/HybridOnramperNitroSpecSwift.hpp Generated C++ wrapper calling into Swift implementation.
nitrogen/generated/ios/c++/HybridOnramperNitroSpecSwift.cpp Generated C++ wrapper compilation unit.
nitrogen/generated/ios/c++/HybridOnramperCheckoutButtonSpecSwift.hpp Generated C++ wrapper for the HybridView calling into Swift.
nitrogen/generated/ios/c++/HybridOnramperCheckoutButtonSpecSwift.cpp Generated C++ wrapper compilation unit.
nitrogen/generated/.gitattributes Marks generated files for GitHub linguist.
nitro.json Adds Nitro config and autolinking declarations for HybridObject/HybridView.
jest.config.js Switches Jest module mapping from Expo to Nitro module mock.
ios/PreparedIntentRegistry.swift Introduces a process-wide registry singleton to share prepared intents across HybridObjects/HybridViews.
ios/OnramperSDKBridge.swift Adds SDK→JS JSON mapping for state/events/errors for Nitro callback transport.
ios/OnramperReactNativeModule.swift Removes Expo Modules native module implementation.
ios/OnramperReactNative.podspec Removes the old ios/-scoped ExpoModulesCore-based podspec.
ios/OnramperCheckoutButtonView.swift Removes the old Expo view manager host.
ios/OnramperCheckoutBridge.swift Adds JSON decoding logic for request/button style into SDK structures.
ios/HybridOnramperNitro.swift Adds Swift Nitro HybridObject implementing the new bridge.
ios/HybridOnramperCheckoutButton.swift Adds Swift Nitro HybridView hosting the SDK SwiftUI button.
ios/Bridging/SessionCredentialsDict.swift Removes Expo Record-based bridging type.
ios/Bridging/PreparedIntentDict.swift Removes Expo Record-based bridging type.
ios/Bridging/OnramperState+Dict.swift Removes old Expo-specific state mapping helpers.
ios/Bridging/OnramperError+JSError.swift Removes old Expo-specific error mapping helpers.
ios/Bridging/OnramperConfigurationDict.swift Removes old Expo Record-based config bridging.
ios/Bridging/CheckoutRequestDict.swift Removes old Expo Record-based request bridging.
ios/Bridging/CheckoutEvent+Dict.swift Removes old Expo-specific event mapping helpers.
ios/Bridging/CheckoutButtonStyleDict.swift Removes old Expo Record-based style bridging.
expo-module.config.json Removes Expo module manifest config (no longer Expo Modules-based).
example/package.json Adds react-native-nitro-modules to the Expo example app deps.
example/package-lock.json Locks added Nitro dependency in the Expo example app.
example/ios/Podfile.properties.json Adjusts example iOS Podfile properties.
example/ios/Podfile.lock Updates pods to include NitroModules and new podspec path.
example/ios/Podfile Disables explicit Swift modules to fix Xcode 16+/26 build issues.
example/ios/OnramperReactNativeExample/PrivacyInfo.xcprivacy Updates privacy manifest entries.
example/ios/OnramperReactNativeExample/Info.plist Reformats + updates URL scheme/bundle identifier values.
example/app.json Enables new arch and applies the package Expo config plugin.
example-bare/tsconfig.json Adds TS config for new bare RN example app.
example-bare/README.md Adds generated bare RN template README.
example-bare/react-native.config.js Adds explicit autolinking config for local file:.. consumption.
example-bare/package.json Adds a new bare RN example app consuming the library via file:...
example-bare/metro.config.js Configures Metro for monorepo-style watchFolders and resolution.
example-bare/jest.config.js Adds Jest config for bare RN example app.
example-bare/ios/Podfile Adds iOS setup + explicit Swift modules disable workaround.
example-bare/ios/OnramperBare/PrivacyInfo.xcprivacy Adds privacy manifest for bare RN example.
example-bare/ios/OnramperBare/OnramperBare.entitlements Adds entitlements file for bare RN example.
example-bare/ios/OnramperBare/LaunchScreen.storyboard Adds launch screen storyboard for bare RN example.
example-bare/ios/OnramperBare/Info.plist Adds iOS Info.plist for bare RN example.
example-bare/ios/OnramperBare/Images.xcassets/Contents.json Adds asset catalog boilerplate.
example-bare/ios/OnramperBare/Images.xcassets/AppIcon.appiconset/Contents.json Adds app icon set metadata.
example-bare/ios/OnramperBare/AppDelegate.swift Adds iOS AppDelegate for bare RN new-arch app.
example-bare/ios/OnramperBare.xcworkspace/contents.xcworkspacedata Adds workspace definition for bare RN example.
example-bare/ios/OnramperBare.xcodeproj/xcshareddata/xcschemes/OnramperBare.xcscheme Adds shared Xcode scheme for bare RN example.
example-bare/ios/.xcode.env Adds Xcode env script for RN build phases.
example-bare/index.js Adds RN entrypoint for bare RN example.
example-bare/Gemfile.lock Adds Ruby deps lockfile for bare RN example iOS tooling.
example-bare/Gemfile Adds Ruby deps for CocoaPods/tooling in bare RN example.
example-bare/env.local.example.ts Adds local env template (secrets) for the bare RN example.
example-bare/createDemoSession.ts Adds helper to create demo sessions for the example app.
example-bare/babel.config.js Adds Babel config for bare RN example.
example-bare/App.tsx Adds full bare RN demo app exercising the new Nitro-based API.
example-bare/app.json Adds RN app metadata for bare RN example.
example-bare/android/settings.gradle Adds Android settings for bare RN example.
example-bare/android/gradlew.bat Adds Gradle wrapper script (Windows).
example-bare/android/gradlew Adds Gradle wrapper script (POSIX).
example-bare/android/gradle/wrapper/gradle-wrapper.properties Adds Gradle wrapper version/pinning.
example-bare/android/gradle.properties Adds Android build flags (incl new arch, Hermes).
example-bare/android/build.gradle Adds Android root build configuration for example.
example-bare/android/app/src/main/res/values/styles.xml Adds Android styles for example.
example-bare/android/app/src/main/res/values/strings.xml Adds Android strings for example.
example-bare/android/app/src/main/res/drawable/rn_edit_text_material.xml Adds Android drawable for RN EditText background.
example-bare/android/app/src/main/java/com/onramperbare/MainApplication.kt Adds Android application class for example.
example-bare/android/app/src/main/java/com/onramperbare/MainActivity.kt Adds Android activity class for example.
example-bare/android/app/src/main/AndroidManifest.xml Adds Android manifest for example.
example-bare/android/app/proguard-rules.pro Adds Proguard rules placeholder for example.
example-bare/android/app/build.gradle Adds Android app build configuration for example.
example-bare/.watchmanconfig Adds Watchman config for example.
example-bare/.prettierrc.js Adds Prettier config for example.
example-bare/.gitignore Adds ignore rules for example.
example-bare/.eslintrc.js Adds ESLint config for example.
example-bare/.bundle/config Adds Bundler config for example.
example-bare/tests/App.test.tsx Adds a basic render test for the bare RN example.
app.plugin.js Adds Expo config plugin to apply iOS deployment target + Swift modules workaround.
.gitignore Ignores bare example local secrets file.
tests/OnramperClient.test.ts Updates unit tests for Nitro-based native mocking and per-client listeners.
tests/mocks/react-native-nitro-modules.ts Adds Nitro module mock for Jest.
tests/mocks/expo-modules-core.ts Removes Expo modules mock (no longer used).
Files not reviewed (2)
  • example-bare/ios/OnramperBare.xcworkspace/contents.xcworkspacedata: Language not supported
  • example/package-lock.json: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread ios/HybridOnramperNitro.swift Outdated
Comment thread ios/HybridOnramperCheckoutButton.swift
Comment thread __tests__/OnramperClient.test.ts
Comment thread __tests__/__mocks__/react-native-nitro-modules.ts
Comment thread __tests__/__mocks__/react-native-nitro-modules.ts
YouCanKeepSilence and others added 8 commits June 1, 2026 15:53
…eployment target

The SDK's real minimum is iOS 16.0 (onramper-sdk Package.swift declares .iOS(.v16);
no @available(iOS 16.4) anywhere) — the 16.4 in the podspec + plugin was an
arbitrary number carried over from the Expo-era example config.

- podspec: s.platforms ios 16.4 -> 16.0 (the package's true floor).
- app.plugin.js: drop the deployment-target override — raising a consumer's
  app-wide minimum iOS is their product decision, not ours. Keep only the
  SWIFT_ENABLE_EXPLICIT_MODULES=NO build-correctness fix.
- docs: package floor is 16.0 (bare RN); note that Expo SDK 56 apps require 16.4
  (Expo's own minimum — surfaced when the example built: expo-modules-core et al.
  'require iOS 16.4'), which is why the Expo example targets 16.4.

Verified: Expo example BUILD SUCCEEDED at 16.4; podspec floor 16.0.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Complete the Expo->Nitro migration on the packaging side. A Nitro module
needs no Expo build tooling, and expo-module-scripts' `prepare` step was
rewriting tsconfig.json on every install (stripping resolveJsonModule and
the nitrogen json include), which broke `tsc` / `npm ci` locally and in CI.

- swap JS/TS build to react-native-builder-bob (commonjs+module+typescript);
  update main/module/types/exports/files for the lib/ layout
- self-contained tsconfig.json (no expo-module-scripts base) — permanently
  ends the tsconfig clobber
- vendor the nitrogen-generated Fabric view config into src/generated via
  scripts/sync-view-config.js (wired into `npm run nitrogen`) so bob's lib/
  output resolves the import correctly; nitrogen stays the source of truth
- drop the unused react-test-renderer devDep and the --legacy-peer-deps flag
  from ci.yml/release.yml (peer resolution is now clean)
- remove the vestigial universe-based .eslintrc.js (lint uses biome)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…n re-hosting

Addresses the PR #1 Copilot review feedback on the checkout flow.

- HybridOnramperNitro: replace the process-wide
  PreparedIntentRegistry.invalidateAll() with a per-instance
  lastPreparedHandle. getCheckoutRequirements now drops only this client's
  prior unconsumed handle before storing the new one (cleared in
  cancelPreparedIntent and dispose), so one client no longer invalidates
  other clients' checkout buttons.
- HybridOnramperCheckoutButton: host() now tears down the previously hosted
  UIHostingController via detachHosted() before installing the new one, so
  re-assigning intentHandle no longer accumulates subviews/constraints or
  leaves the old controller childed to the parent VC.
- Tests: cover getCheckoutRequirements (JSON request/style serialization,
  quote parsing, button element, buttonStyle default, native error wrapping)
  and cancelPreparedIntent forwarding; add both methods to the Nitro mock.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…od path

- example-bare: declare the App Attest entitlement
  (com.apple.developer.devicecheck.appattest-environment = development) so
  on-device checkout works with the SDK, matching the Expo example.
- example Podfile.lock: correct the NitroModules pod path from
  ../../node_modules to ../node_modules and refresh the OnramperReactNative
  checksum.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The auto GITHUB_TOKEN is scoped to this repo only and can't read the
private onramper/onramper-ios release. Pass a fine-grained PAT via
GH_TOKEN so `gh release download` can authenticate cross-repo. Remove
once onramper-ios is public.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…o app to example-expo

Since the Nitro migration the bare React Native app is the canonical
example, so make the directory layout reflect that:

- example (Expo)      -> example-expo
- example-bare (bare) -> example

Rebrand the bare app's identity OnramperBare -> OnramperExample across
package.json, app.json, Android rootProject.name / app_name,
getMainComponentName, iOS moduleName, and the iOS target / scheme /
project / workspace / Podfile target. Android applicationId
(com.onramperbare) and iOS bundle id (com.onramper.demo.react-native)
are intentionally unchanged so signing/install identity stays stable.

Disambiguate the Expo app's package name to
onramper-react-native-example-expo, and replace its stock RN-CLI README
with Expo-specific launch steps (prebuild + dev client, env.local.ts,
xcframework fetch).

Update root references: .gitignore example/* -> example-expo/* (Expo
artifacts) and example-bare/env.local.ts -> example/env.local.ts;
tsconfig exclude example-bare -> example-expo.

Both apps verified building: example (xcodebuild) and example-expo
(expo run:ios) build and launch on simulator.
Validated that @onramper/react-native builds, bundles, and renders on a
physical device at RN 0.79.7 + React 19 (the lowest RN that ships React
19). The library uses no React-19-only or 0.85-only APIs, and the
generated Nitro view degrades gracefully below RN 0.82.

Update README and INTEGRATION docs to match (RN 0.79+; New Architecture
is default on RN 0.76+).
@YouCanKeepSilence YouCanKeepSilence merged commit 840ffb3 into master Jun 2, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants